#pragma once

#include <iostream>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <strings.h>
#include <unistd.h>
#include <functional>

using namespace std;

enum errornum
{
    SOCK_FAILED = 1,
    BIND_FAILED,
    LISTEN_FAILED,
    ACCEPT_FAILED,
    FORK_FAILED,
    GETREQ_FAIDED
};

class httpserver
{
public:
    typedef function<void(int)> func;
    // 构造
    httpserver(uint16_t serverport, func callback)
        : _serverport(serverport), _listensock(-1), _callback(callback)
    {
        // 1、创建套接字
        _listensock = socket(AF_INET, SOCK_STREAM, 0);
        if (_listensock == -1) // 套接字创建失败
        {
            cerr << "套接字创建失败" << endl;
            exit(SOCK_FAILED);
        }

        cout << "创建套接字成功，sock:" << _listensock << endl;

        // 2、绑定套接字
        // 2.1 构建服务器属性结构
        struct sockaddr_in serverinfor; // 服务器信息
        bzero(&serverinfor, sizeof(serverinfor));
        serverinfor.sin_family = AF_INET;
        serverinfor.sin_addr.s_addr = htonl(INADDR_ANY);
        serverinfor.sin_port = htons(_serverport);
        // 2.2绑定套接字
        int n = bind(_listensock, (struct sockaddr *)&serverinfor, sizeof(serverinfor));
        if (n < 0)
        {
            cerr << "套接字绑定失败" << endl;
            exit(BIND_FAILED);
        }

        cout << "绑定套接字成功" << endl;

        // 3、设置套接字为监听状态
        n = listen(_listensock, 5);
        if (n < 0)
        {
            cerr << "设置套接字监听状态失败" << endl;
            exit(LISTEN_FAILED);
        }

        cout << "设置套接字为监听状态成功" << endl;
    }

    // 启动
    void start()
    {
        while (true)
        {
            // 1、构建客户端属性结构
            struct sockaddr_in clientinfor;      // 服务器信息
            socklen_t len = sizeof(clientinfor); // 服务器属性结构大小
            bzero(&clientinfor, sizeof(clientinfor));

            // 2、获取链接
            int sock = accept(_listensock, (struct sockaddr *)&(clientinfor), &len);
            if (sock < 0)
            {
                cerr << "获取链接失败" << endl;
                exit(ACCEPT_FAILED);
            }

            cout << "获取链接成功，sock:" << sock << endl;

            // 3、创建子进程，让子进程接收请求、发送响应
            int pid = fork();
            if (pid < 0)
            {
                cerr << "fork failed" << endl;
                exit(FORK_FAILED);
            }

            // fork成功
            if (pid == 0) // 子进程
            {
                close(_listensock); // 子进程不需要使用_listensock，将其关闭
                if (fork() > 0)     // 子进程创建孙进程
                    exit(0);        // 子进程直接退出

                // 要么fock失败，仍是子进程；要么fork成功，子进程已退出，当前为孙进程
                _callback(sock); // 孙进程从sock套接字中接收请求，发送响应
                close(sock);
                exit(0);//孙进程执行完任务后终止
            }

            // 父进程
            close(sock); // 父进程不需要使用sock套接字，直接关闭sock

            // 父进程阻塞式等待子进程，由于子进程创建孙进程后立即退出，因此很快就能等待成功
            waitpid(pid, nullptr, 0);
        }
    }

    // 删除拷贝构造
    httpserver(const httpserver &) = delete;

    // 删除赋值重载
    httpserver &operator=(const httpserver &) = delete;

    // 析构
    ~httpserver()
    {
        close(_listensock); // 关闭文件
    }

private:
    int _listensock;      // 监听端口号
    uint16_t _serverport; // 服务器端口号
    func _callback;//回调函数
};